#ifndef _MEMCACHE_OP_H
#define _MEMCACHE_OP_H


// #include <libmemcache/memcache.h>
#include <iostream>
#include <vector>
#include <string>

#include <mcache/mcache.h>

using namespace std;
using namespace mcache;

#define TCACHE mcache::Cache

#define CONN_CHECK_RET(retv) ReConnect(); if(!binited) return retv; TCACHE &cache=*pcache;

struct MemCacheOperator
{
   TCACHE *pcache;
   bool binited;
   vector<string> hosts;
   MemCacheOperator():binited(false) { pcache=NULL; }
   operator bool() { return binited; }
   int InitServerList(const string& servlist)
   {
	  if( binited ) return hosts.size();
	  string tmp;
	  for( int i=0 ; i<servlist.size() ; i++ )
	  {
	     if ( servlist[i] == ',' )
		 {
		     if( !tmp.empty() )
				 hosts.push_back(tmp);
		     
			 tmp="";
		 }
		 else
		 {
		    tmp+=servlist[i];
		 }
	  }

	  if( !tmp.empty() )
		   hosts.push_back(tmp);

      return ReConnect();
	}
   
   int ReConnect()
   {
	  if( binited ) return hosts.size();

	  if( pcache )
		  delete pcache;
	
	  pcache = new TCACHE;
	  TCACHE &cache=*pcache;
	  try {
		  for( int i=0; i< hosts.size() ; i++ )
		  { 
			   cache.addServer(hosts[i]);
		  }
		  if( hosts.size() > 0 )
		      binited = true;
	  }
	  catch (const exception &e )
	  {
		  DEBUG_P(LOG_ERROR,"reinit cache error: %s",e.what());
	  }
	  catch (...)
	  {
           DEBUG_P(LOG_ERROR,"reinit cache error");
	  }
	 
	  DEBUG_P(LOG_NORMAL,"Init MemCache %s.",binited?"OK":"*failed*"); 

	  return hosts.size();

	}
	bool Load(const string& key, netx::EvBuffer &out)
	{
       CONN_CHECK_RET(false);
		
	   try {
			string buffstr=cache.get( key );
			if( !buffstr.empty() )
			{
				out.Add(buffstr.data(),buffstr.length());
				return true;
			}
		}
		catch (const exception &e)
		{
			DEBUG_P(LOG_ERROR,"error cache load: %s",e.what() );
		}
		
		return false; // not found.
	}
	bool AddNew(const string &key, netx::EvBuffer &bf,int timeout)
	{
       CONN_CHECK_RET(false);

		string  tmpstr;
		tmpstr.resize(bf.Length());
		int leng=bf.Length();
		memcpy( (char*)(tmpstr.data()) , bf.Data() , leng );
		try {
			  int errret = cache.add2( key, tmpstr, timeout );
			  if( errret )
			  {
			    DEBUG_P(LOG_ERROR,"fail cache add %s,timeout=%d,errret=%d",key.c_str(),timeout,errret);
                //if( errret != MEMCACHED_NOTSTORED )
				if( errret != 1 )
				{
					DEBUG_P(LOG_ERROR,"fail cache add %s errret=%d, Reinitmcache",key.c_str(),errret);
					binited=false;
				}
				return false;
			  }
			  return true;
		}
		catch (const exception &e)
		{
			DEBUG_P(LOG_ERROR," exception:cache add %s,%d,%s",key.c_str(),timeout,e.what());
			binited = false;
		}
		return false;
	}
	bool Store(const string &key, netx::EvBuffer &bf,int timeout)
	{
		CONN_CHECK_RET(false);
		
		string  tmpstr;
		tmpstr.resize(bf.Length());
		int leng=bf.Length();
		memcpy( (char*)(tmpstr.data()) , bf.Data() , leng );
		try {
			if( !cache.set( key, tmpstr, timeout ) )
			{
			    DEBUG_P(LOG_ERROR,"fail cache set %s,timeout=%d",key.c_str(),timeout);
			}else
			{
			   return true;
			}
		}
		catch (const exception &e)
		{
			DEBUG_P(LOG_ERROR," exception:cache store %s,%d,%s",key.c_str(),timeout,e.what());
		}
	    binited=false;	
		return false;
	}
};

#endif

